<?php
/**
 * fly
 * Copyright By 5920Team (http://www.5920.me)
 * User: yu@5920.me
 * Date: 13-9-29
 * Time: 下午5:03
 */


class SqlBuilder
{
    /**
     * @var string
     */
    private $prefix;

    /**
     * @var array
     */
    private $sqlPreBuild;


    /**
     * quote \ replace
     * @param $string
     * @return string
     */
    private function quoteValue($string)
    {
        return '\'' . str_replace(array('\'', '\\'), array('\'\'', '\\\\'), $string) . '\'';
    }

    public function getAction()
    {
        return $this->sqlPreBuild['action'];
    }
    public function setCount()
    {
        $this->sqlPreBuild['fields'] = 'count(*) as count';
        return $this;
    }

    /**
     * @param string $prefix
     */
    public function __construct($prefix = '')
    {
        $this->prefix = $prefix;
        $this->sqlPreBuild = array(
            'action' => NULL,
            'table'  => NULL,
            'fields' => '*',
            'join'   => array(),
            'where'  => NULL,
            'limit'  => NULL,
            'offset' => NULL,
            'order'  => NULL,
            'row'   => array(),
            'rows'   => array()
        );
    }

    /**
     * @param $table
     * @return SqlBuilder
     */
    public function insert($table)
    {
        $this->sqlPreBuild['action'] = 'INSERT';
        $this->sqlPreBuild['table'] = $this->prefix . $table;
        return $this;
    }

    /**
     * @param $table
     * @return SqlBuilder
     */
    public function update($table)
    {
        $this->sqlPreBuild['action'] = 'UPDATE';
        $this->sqlPreBuild['table'] = $this->prefix . $table;
        return $this;
    }

    /**
     * @param $table
     * @return SqlBuilder
     */
    public function delete($table)
    {
        $this->sqlPreBuild['action'] = 'DELETE';
        $this->sqlPreBuild['table'] = $this->prefix . $table;
        return $this;
    }

    /**
     * @param string $field
     * @return SqlBuilder
     */
    public function select($field = '*')
    {
        $this->sqlPreBuild['action'] = 'SELECT';
        $args = func_get_args();
        $this->sqlPreBuild['fields'] = implode(', ', $args);
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function where()
    {
        $condition = func_get_arg(0);
        $condition = str_replace('?', "%s", $condition);

        $operator = empty($this->sqlPreBuild['where']) ? ' WHERE ' : ' AND';
        if (func_num_args() <= 1)
        {
            $this->sqlPreBuild['where'] .= $operator . ' (' . $condition . ')';
        } else {
            $args = func_get_args();

            array_shift($args);
            $this->sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, array_map(array($this, 'quoteValue'), $args)) . ')';
        }
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function orWhere()
    {
        $condition = func_get_arg(0);
        $condition = str_replace('?', "%s", $condition);

        $operator = empty($this->sqlPreBuild['where']) ? ' WHERE ' : ' OR';
        if (func_num_args() <= 1)
        {
            $this->sqlPreBuild['where'] .= $operator . ' (' . $condition . ')';
        } else {
            $args = func_get_args();

            array_shift($args);
            $this->sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, array_map(array($this, 'quoteValue'), $args)) . ')';
        }
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function limit($limit)
    {
        $this->sqlPreBuild['limit'] = intval($limit);
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function offset($offset)
    {
        $this->sqlPreBuild['offset'] = intval($offset);
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function order($orderBy, $sort = 'ASC')
    {
        $this->sqlPreBuild['order'] = ' ORDER BY ' . $orderBy . ' ' . $sort;
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function page($page, $pageSize)
    {
        $pageSize = intval($pageSize);
        $this->sqlPreBuild['limit'] = $pageSize;
        $this->sqlPreBuild['offset'] = (max(intval($page), 1) - 1) * $pageSize;
        return $this;
    }

    /**
     * @param $val
     * @param string $pri
     * @return SqlBuilder
     */
    public function pri($id, $pri = 'id')
    {
        if(is_array($id))
        {
            foreach($id as $val)
            {
                $this->orwhere($pri . ' = ?', $val);
            }
        }
        else
        {
            $this->where($pri . ' = ?', $id);
        }
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function row($row)
    {
        foreach ($row as $key => $val) {
            $this->sqlPreBuild['row'][$key] = is_null($val) ? 'NULL' : $this->quoteValue($val);
        }
        return $this;
    }

    /**
     * @return SqlBuilder
     */
    public function rows($rows)
    {
        foreach ($rows as  $row) {
            $arr = array();
            foreach ($row as $key => $val) {
                $arr[$key] = is_null($val) ? 'NULL' : $this->quoteValue($val);
            }
            $this->sqlPreBuild['rows'][] = $arr;
        }
        return $this;
    }

    /**
     * @param $table
     * @return SqlBuilder
     */
    public function from($table)
    {
        $this->sqlPreBuild['table'] = $this->prefix . $table;
        return $this;
    }

    /**
     * @return null|string
     */
    public function __tostring()
    {
         switch ($this->sqlPreBuild['action']) {
            case 'SELECT':
                $this->sqlPreBuild['limit'] = (0 == strlen($this->sqlPreBuild['limit'])) ? NULL : ' LIMIT ' . $this->sqlPreBuild['limit'];
                $this->sqlPreBuild['offset'] = (0 == strlen($this->sqlPreBuild['offset'])) ? NULL : ' OFFSET ' . $this->sqlPreBuild['offset'];

                return 'SELECT '
                . $this->sqlPreBuild['fields']
                . ' FROM '
                . $this->sqlPreBuild['table']
                . $this->sqlPreBuild['where']
                . $this->sqlPreBuild['order']
                . $this->sqlPreBuild['limit']
                . $this->sqlPreBuild['offset'];
            case 'INSERT':
                if(empty($this->sqlPreBuild['rows']))
                {
                    $query = 'INSERT INTO '
                    . $this->sqlPreBuild['table']
                    . '(' . implode(', ', array_keys($this->sqlPreBuild['row'])) . ')'
                    . ' VALUES '
                    . '(' . implode(', ', array_values($this->sqlPreBuild['row'])) . ')';
                }
                else
                {
                    $query = 'INSERT INTO '
                        . $this->sqlPreBuild['table']
                        . '(' . implode(', ', array_keys($this->sqlPreBuild['rows'][0])) . ')'
                        . ' VALUES ';
                    foreach($this->sqlPreBuild['rows'] as $row)
                    {
                            $values[] = '(' . implode(', ', array_values($row)) . ')';
                    }
                    $query .= implode(', ', $values);
                }
                return $query;
            case 'DELETE':
                return 'DELETE FROM '
                . $this->sqlPreBuild['table']
                . $this->sqlPreBuild['where'];
            case 'UPDATE':
                $columns = array();
                if (isset($this->sqlPreBuild['row'])) {
                    foreach ($this->sqlPreBuild['row'] as $key => $val) {
                        $columns[] = "$key = $val";
                    }
                }
                return 'UPDATE '
                . $this->sqlPreBuild['table']
                . ' SET ' . implode(', ', $columns)
                . $this->sqlPreBuild['where'];
            default:
                return NULL;
        }
    }
}